﻿using SharpStockLib.DataAccess.Providers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using SharpStockLib.Data;
using System.Reactive.Linq;
using System.Data.SQLite;
using System.Collections.Generic;

namespace SharpStockTests
{
    
    
    /// <summary>
    ///This is a test class for SQLiteProviderTest and is intended
    ///to contain all SQLiteProviderTest Unit Tests
    ///</summary>
    [TestClass()]
    public class SQLiteProviderTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for GetHistoricalDataAsync
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_FullDataForStock()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            const string instrumentName = "IBM";

            long totalRows = GetCountFromEOD(pathToDB, instrumentName);

            using (SQLiteProvider target = new SQLiteProvider(pathToDB))
            {
                IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, null, null);
                long cpt = 0;

                foreach (IData data in actual)
                {
                    Assert.IsTrue(data.Close > 0);
                    cpt++;
                }

                Assert.AreEqual(totalRows, cpt);
            }
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with both start and end dates
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithBothDates()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            string instrumentName = "IBM";

            DateTime startDate = new DateTime(2000, 6, 6);
            DateTime endDate = new DateTime(2001, 6, 9);

            long totalRows = GetCustomCountFromEOD(pathToDB, "select count(*) from eod where symbol = '" + instrumentName + "' and date >= '" + startDate.ToString("yyyy-MM-dd") + "' and date <= '" + endDate.ToString("yyyy-MM-dd") + "'");

            using (SQLiteProvider target = new SQLiteProvider(pathToDB))
            {
                IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, startDate, endDate);
                long cpt = 0;

                foreach (IData data in actual)
                {
                    Assert.IsTrue(data.Close > 0);
                    cpt++;
                }

                // Counts should be equal to 255 or something.
                Assert.AreEqual(totalRows, cpt);
            }
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with start date
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithStartDate()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            string instrumentName = "IBM";

            DateTime startDate = new DateTime(2000, 6, 6);

            long totalRows = GetCustomCountFromEOD(pathToDB, "select count(*) from eod where symbol = '" + instrumentName + "' and date >= '" + startDate.ToString("yyyy-MM-dd") + "'");

            using (SQLiteProvider target = new SQLiteProvider(pathToDB))
            {
                IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, startDate, null);
                long cpt = 0;

                foreach (IData data in actual)
                {
                    Assert.IsTrue(data.Close > 0);
                    cpt++;
                }

                // Counts should be equal to 2944 or something.
                Assert.AreEqual(totalRows, cpt);
            }
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync with end date
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_WithEndDate()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            string instrumentName = "IBM";

            DateTime endDate = new DateTime(2001, 6, 9);

            long totalRows = GetCustomCountFromEOD(pathToDB, "select count(*) from eod where symbol = '" + instrumentName + "' and date <= '" + endDate.ToString("yyyy-MM-dd") + "'");

            using (SQLiteProvider target = new SQLiteProvider(pathToDB))
            {
                IEnumerable<IData> actual = target.GetHistoricalData(instrumentName, null, endDate);
                long cpt = 0;

                foreach (IData data in actual)
                {
                    Assert.IsTrue(data.Close > 0);
                    cpt++;
                }

                // Counts should be equal to 760 or something.
                Assert.AreEqual(totalRows, cpt);
            }
        }

        /// <summary>
        ///A test for GetHistoricalDataAsync that fails when connecting
        ///</summary>
        [TestMethod()]
        public void GetHistoricalDataAsyncTest_FailConnection()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\NON EXISTING DATABASE.db";

            try
            {
                using (SQLiteProvider target = new SQLiteProvider(pathToDB))
                {
                    // Should not get here
                    Assert.Fail();
                }
            }
            catch (Exception e)
            {
                Assert.IsInstanceOfType(e, typeof(SQLiteException));
            }
        }


        private long GetCountFromEOD(string pathToDb, string instrumentName)
        {
            return GetCustomCountFromEOD(pathToDb, "select count(*) from eod where symbol = '" + instrumentName + "'");
        }

        private long GetCustomCountFromEOD(string pathToDb, string countQuery)
        {
            SQLiteConnection connection = new SQLiteConnection("Data Source=" + pathToDb + ";Version=3;");
            connection.Open();
            SQLiteCommand cmd = connection.CreateCommand();
            cmd.CommandText = countQuery;
            object count = cmd.ExecuteScalar();
            cmd.Dispose();
            connection.Close();
            connection.Dispose();

            return (long)count;
        }

        /// <summary>
        ///A test for FullLoad
        ///</summary>
        [TestMethod()]
        public void FullLoadTest()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            SQLiteProvider target = new SQLiteProvider(pathToDB);
            List<string> symbols = target.ListStocks();

            Dictionary<string, List<IData>> expected = new Dictionary<string, List<IData>>();
            expected["NKE"] = new List<IData>();
            expected["INTC"] = new List<IData>();
            expected["IBM"] = new List<IData>();
            expected["KO"] = new List<IData>();

            Dictionary<string, List<IData>> actual = target.FullLoad(symbols);

            foreach(string symbol in expected.Keys)
                Assert.IsTrue(actual.ContainsKey(symbol));
        }

        /// <summary>
        ///A test for ListStocks
        ///</summary>
        [TestMethod()]
        public void ListStocksTest()
        {
            string pathToDB = testContextInstance.DeploymentDirectory + "\\quotes.db";
            SQLiteProvider target = new SQLiteProvider(pathToDB);

            List<string> expected = new List<string>();
            expected.Add("NKE");
            expected.Add("INTC");
            expected.Add("KO");
            expected.Add("IBM");
            List<string> actual = target.ListStocks();

            CollectionAssert.AreEquivalent(expected, actual);
        }
    }
}
